import type { DynamicHideMetaOptions } from '../../../../lib/dynamic_hide'
import type { PageType } from '../../../../lib/page_handler/type'
import type {
  BaseStyleConfig,
  IPersonalizationItemConfig,
  PlatformTypeValue,
} from '../../../../types/interfaces'
import { TextInput } from '../../../../components/text_input'
import { ElementCSSHandler } from '../../../../element/service/element_css_handler'
import { ElementHideCssOperation } from '../../../../element/service/types'
import { UserPref } from '../../../../lib/abstract'
import { DynamicHide } from '../../../../lib/dynamic_hide'
import { BaiduPageType } from '../../../../lib/page_handler/platform/baidu/types'
import { InjectorType } from '../../../../lib/style_injector'
import { ToolKit } from '../../../../lib/utils/toolkit'
import {
  BodyAttrs,
  BodyClasses,
  ELEMENT_HIDE_TYPE,
  ELEMENT_SAVE_CONFIG,
  ElementConfigSource,
  ElementSelectorDOMScopeType,
  ElementSelectorType,
  logger,
  SUPPORTED_PLATFORMS,
  VALID_RESULT,
} from '../../../../types/constants'

export class ElementHide extends UserPref {
  // @Decorators.Identity
  readonly id = 'element_hide'
  readonly name = 'ElementHide'
  // @Decorators.InheritedCoreConfig
  readonly notSupportedPages: Partial<Record<PlatformTypeValue, PageType[]>> | undefined = {
    [SUPPORTED_PLATFORMS.BAI_DU]: [
      BaiduPageType.NotFound,
    ],
  }

  // @Decorators.InheritedConfig
  readonly styleConfigKey = 'elementHide'
  readonly cssProperty = ''
  readonly cssValueSuffix = ''
  // 由于文本输入使用的是失焦事件和回车事件，不会短时间高频触发事件，所以不需要防抖保存处理，故置为0
  readonly debouncedSaveTimeout: number = 0
  // @Decorators.Dependency
  private readonly CSSHandler: ElementCSSHandler = ElementCSSHandler.getInstance()
  // @Decorators.Config
  private readonly valueSeparator: string = '|||'

  constructor(config: IPersonalizationItemConfig) {
    super(config)
  }

  createComponent(config: BaseStyleConfig, value: string, _mode: string, debouncedSave: (() => void) & { flush: () => void }): TextInput {
    const id = this.generateId(config.styleVar)
    return new TextInput({
      id,
      label: '隐藏元素',
      type: 'textarea',
      rows: 8,
      // 示例：.article-header-box|||#blogColumnPayAdvert
      placeholder: `输入自定义选择器，支持JQuery语法，多个用${this.valueSeparator}分隔（如：#toolbarBox${this.valueSeparator}.toolbarBox）`,
      value,
      onChange: (value) => {
        this.cachedValues.set(id, String(value))
        debouncedSave()
      },
    })
  }

  // 填写内容复杂，暂不需要额外的校验逻辑
  handleCheck(_value: string): { status: ValidResultType, error: string } {
    // 支持输入为空或长度为0
    return { status: VALID_RESULT.VALID.value, error: '' }
  }

  applyStyles(): void {
    this.getInstanceIds().forEach(async (id) => {
      const failedSelectors: DynamicHideMetaOptions = []
      const { value } = this.getStorageValues(id)

      // 1. 添加标识类名
      document.body.classList.toggle(BodyClasses.HAS_CUSTOM_HIDDEN, !!value)

      // 2. 显示所有自定义隐藏元素
      ToolKit.ui.element.showElement(`[${BodyAttrs.HIDE_TYPE}="${ELEMENT_HIDE_TYPE.CUSTOM}"]`, { clearChildStyles: false })
      await this.CSSHandler.clearCustomSelectors()

      // 3. 隐藏合法元素
      const selectors = value.split(this.valueSeparator)
        .map(s => s.trim())
        .filter(s => s.length > 0)

      if (selectors.length === 0) {
        logger.debug(`[${this.name}] 隐藏元素选择器为空，跳过处理`)
        return
      }

      // 3.1 使用 CSS 注入隐藏元素
      this.CSSHandler.addRules(selectors.map((selector, index) => ({
        name: `自定义规则-${index + 1}`,
        domScope: ElementSelectorDOMScopeType.Document,
        selectorType: ElementSelectorType.Class,
        selector,
        source: ElementConfigSource.Custom,
        injectorType: InjectorType.Standard,
        operation: ElementHideCssOperation.Inject,
      })))

      // 3.2 首次尝试隐藏
      for (const selector of selectors) {
        // 开始隐藏元素
        ToolKit.ui.element.hideElement(selector, { clearChildStyles: false, type: ELEMENT_HIDE_TYPE.CUSTOM })

        // 检查是否成功隐藏
        if ($(selector).is(':visible')) {
          failedSelectors.push({
            type: ELEMENT_SAVE_CONFIG.ELEMENT.id,
            domScope: ElementSelectorDOMScopeType.Document,
            hostSelector: '',
            selector,
            source: ElementConfigSource.Custom,
          })
        }
      }

      // 3.3 对首次隐藏失败的选择器进行轮询处理
      if (failedSelectors.length > 0) {
        logger.info(`[${this.name}] 开始轮询处理 ${failedSelectors.length} 个元素`)
        DynamicHide.getInstance().pollDynamicHideElements(failedSelectors, {
          type: ELEMENT_HIDE_TYPE.CUSTOM,
        })
      }
    })
  }
}
